From 78ef1b2ab78a379d14676c6aec866721b6b88e52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Mon, 16 Oct 2023 12:30:07 +0200 Subject: [PATCH] Apply browser-targeted WordPress patches via Blueprints, not in remote.html. Enables patching arbitrary WordPress bundles for compatibility with web browsers. Without this PR, remote.html applies these patch right after the WordPress module is loaded into the /wordpress VFS directory. However, in #700 we want to enable using an arbitrary WordPress build from any PR in wordpress-develop. We must, thus, expose a way of applying the necessary patches. Testing instructions 1. Start Playground, log out 2. Go to /wp-login.php 3. Confirm there's a message explaining what login credentials to use --- .../steps/apply-wordpress-patches/index.ts | 74 +++++++++ .../playground/compile-wordpress/Dockerfile | 2 +- .../src/lib/web-wordpress-patches/index.ts | 98 ------------ .../1-show-admin-credentials-on-wp-login.php | 15 -- ...ges-for-plugins-and-themes-directories.php | 35 ----- ...-frame-should-target-playground-iframe.php | 21 --- .../mu-plugins/add_requests_transport.php | 24 --- .../includes/requests_transport_dummy.php | 43 ------ .../includes/requests_transport_fetch.php | 145 ------------------ .../remote/src/lib/worker-thread.ts | 2 - 10 files changed, 75 insertions(+), 384 deletions(-) delete mode 100644 packages/playground/remote/src/lib/web-wordpress-patches/index.ts delete mode 100644 packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php delete mode 100644 packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/2-nice-error-messages-for-plugins-and-themes-directories.php delete mode 100644 packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/3-links-targeting-top-frame-should-target-playground-iframe.php delete mode 100644 packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/add_requests_transport.php delete mode 100644 packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/includes/requests_transport_dummy.php delete mode 100644 packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/includes/requests_transport_fetch.php diff --git a/packages/playground/blueprints/src/lib/steps/apply-wordpress-patches/index.ts b/packages/playground/blueprints/src/lib/steps/apply-wordpress-patches/index.ts index 6049d8dcec..8464a8d8da 100644 --- a/packages/playground/blueprints/src/lib/steps/apply-wordpress-patches/index.ts +++ b/packages/playground/blueprints/src/lib/steps/apply-wordpress-patches/index.ts @@ -3,6 +3,19 @@ import { StepHandler } from '..'; import { updateFile } from '../common'; import { defineWpConfigConsts } from '../define-wp-config-consts'; +/** @ts-ignore */ +import transportFetch from './wp-content/mu-plugins/includes/requests_transport_fetch.php?raw'; +/** @ts-ignore */ +import transportDummy from './wp-content/mu-plugins/includes/requests_transport_dummy.php?raw'; +/** @ts-ignore */ +import addRequests from './wp-content/mu-plugins/add_requests_transport.php?raw'; +/** @ts-ignore */ +import showAdminCredentialsOnWpLogin from './wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php?raw'; +/** @ts-ignore */ +import niceErrorMessagesForPluginsAndThemesDirectories from './wp-content/mu-plugins/2-nice-error-messages-for-plugins-and-themes-directories.php?raw'; +/** @ts-ignore */ +import linksTargetingTopFrameShouldTargetPlaygroundIframe from './wp-content/mu-plugins/3-links-targeting-top-frame-should-target-playground-iframe.php?raw'; + /** * @private */ @@ -15,6 +28,7 @@ export interface ApplyWordPressPatchesStep { disableSiteHealth?: boolean; disableWpNewBlogNotification?: boolean; makeEditorFrameControlled?: boolean; + prepareForRunningInsideWebBrowser?: boolean; } export const applyWordPressPatches: StepHandler< @@ -47,6 +61,9 @@ export const applyWordPressPatches: StepHandler< `${patch.wordpressPath}/wp-includes/js/dist/block-editor.min.js`, ]); } + if (options.prepareForRunningInsideWebBrowser === true) { + await patch.prepareForRunningInsideWebBrowser(); + } }; class WordPressPatcher { @@ -120,6 +137,63 @@ class WordPressPatcher { `${contents} function wp_new_blog_notification(...$args){} ` ); } + + async prepareForRunningInsideWebBrowser() { + await updateFile( + this.php, + `${this.wordpressPath}/wp-config.php`, + (contents) => `${contents} define('USE_FETCH_FOR_REQUESTS', false);` + ); + + // Force the fsockopen and cUrl transports to report they don't work: + const transports = [ + `${this.wordpressPath}/wp-includes/Requests/Transport/fsockopen.php`, + `${this.wordpressPath}/wp-includes/Requests/Transport/cURL.php`, + ]; + for (const transport of transports) { + // One of the transports might not exist in the latest WordPress version. + if (!(await this.php.fileExists(transport))) { + continue; + } + await updateFile(this.php, transport, (contents) => + contents.replace( + 'public static function test', + 'public static function test( $capabilities = array() ) { return false; } public static function test2' + ) + ); + } + + // Add fetch and dummy transports for HTTP requests + await this.php.mkdirTree( + `${this.wordpressPath}/wp-content/mu-plugins/includes` + ); + await this.php.writeFile( + `${this.wordpressPath}/wp-content/mu-plugins/includes/requests_transport_fetch.php`, + transportFetch + ); + await this.php.writeFile( + `${this.wordpressPath}/wp-content/mu-plugins/includes/requests_transport_dummy.php`, + transportDummy + ); + await this.php.writeFile( + `${this.wordpressPath}/wp-content/mu-plugins/add_requests_transport.php`, + addRequests + ); + + // Various tweaks + await this.php.writeFile( + `${this.wordpressPath}/wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php`, + showAdminCredentialsOnWpLogin + ); + await this.php.writeFile( + `${this.wordpressPath}/wp-content/mu-plugins/2-nice-error-messages-for-plugins-and-themes-directories.php`, + niceErrorMessagesForPluginsAndThemesDirectories + ); + await this.php.writeFile( + `${this.wordpressPath}/wp-content/mu-plugins/3-links-targeting-top-frame-should-target-playground-iframe.php`, + linksTargetingTopFrameShouldTargetPlaygroundIframe + ); + } } function randomString(length: number) { diff --git a/packages/playground/compile-wordpress/Dockerfile b/packages/playground/compile-wordpress/Dockerfile index 6369e2229c..7032219bd7 100644 --- a/packages/playground/compile-wordpress/Dockerfile +++ b/packages/playground/compile-wordpress/Dockerfile @@ -62,7 +62,7 @@ RUN cd wordpress && \ -o -name '*.ttf' -o -name '*.txt' -o -name '*.woff' \ -o -name '*.woff2' -o -name '*.jpeg' -o -name '*.jpg' \ \) \ - # Preserve the wp-admin SVG files that are read by PHP + # Preserve the wp-admin SVG files that are read by PHP -not -path '*/wp-admin/images/*.svg' \ -delete diff --git a/packages/playground/remote/src/lib/web-wordpress-patches/index.ts b/packages/playground/remote/src/lib/web-wordpress-patches/index.ts deleted file mode 100644 index a478e62c8b..0000000000 --- a/packages/playground/remote/src/lib/web-wordpress-patches/index.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { UniversalPHP } from '@php-wasm/universal'; - -/** @ts-ignore */ -import transportFetch from './wp-content/mu-plugins/includes/requests_transport_fetch.php?raw'; -/** @ts-ignore */ -import transportDummy from './wp-content/mu-plugins/includes/requests_transport_dummy.php?raw'; -/** @ts-ignore */ -import addRequests from './wp-content/mu-plugins/add_requests_transport.php?raw'; -/** @ts-ignore */ -import showAdminCredentialsOnWpLogin from './wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php?raw'; -/** @ts-ignore */ -import niceErrorMessagesForPluginsAndThemesDirectories from './wp-content/mu-plugins/2-nice-error-messages-for-plugins-and-themes-directories.php?raw'; -/** @ts-ignore */ -import linksTargetingTopFrameShouldTargetPlaygroundIframe from './wp-content/mu-plugins/3-links-targeting-top-frame-should-target-playground-iframe.php?raw'; - -import { DOCROOT } from '../config'; - -export function applyWebWordPressPatches(php: UniversalPHP) { - const patch = new WordPressPatcher(php, DOCROOT); - - patch.replaceRequestsTransports(); -} - -class WordPressPatcher { - php: UniversalPHP; - wordpressPath: string; - - constructor(php: UniversalPHP, wordpressPath: string) { - this.php = php; - this.wordpressPath = wordpressPath; - } - - async replaceRequestsTransports() { - await updateFile( - this.php, - `${this.wordpressPath}/wp-config.php`, - (contents) => `${contents} define('USE_FETCH_FOR_REQUESTS', false);` - ); - - // Force the fsockopen and cUrl transports to report they don't work: - const transports = [ - `${this.wordpressPath}/wp-includes/Requests/Transport/fsockopen.php`, - `${this.wordpressPath}/wp-includes/Requests/Transport/cURL.php`, - ]; - for (const transport of transports) { - // One of the transports might not exist in the latest WordPress version. - if (!(await this.php.fileExists(transport))) { - continue; - } - await updateFile(this.php, transport, (contents) => - contents.replace( - 'public static function test', - 'public static function test( $capabilities = array() ) { return false; } public static function test2' - ) - ); - } - - // Add fetch and dummy transports for HTTP requests - await this.php.mkdirTree( - `${this.wordpressPath}/wp-content/mu-plugins/includes` - ); - await this.php.writeFile( - `${this.wordpressPath}/wp-content/mu-plugins/includes/requests_transport_fetch.php`, - transportFetch - ); - await this.php.writeFile( - `${this.wordpressPath}/wp-content/mu-plugins/includes/requests_transport_dummy.php`, - transportDummy - ); - await this.php.writeFile( - `${this.wordpressPath}/wp-content/mu-plugins/add_requests_transport.php`, - addRequests - ); - - // Various tweaks - await this.php.writeFile( - `${this.wordpressPath}/wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php`, - showAdminCredentialsOnWpLogin - ); - await this.php.writeFile( - `${this.wordpressPath}/wp-content/mu-plugins/2-nice-error-messages-for-plugins-and-themes-directories.php`, - niceErrorMessagesForPluginsAndThemesDirectories - ); - await this.php.writeFile( - `${this.wordpressPath}/wp-content/mu-plugins/3-links-targeting-top-frame-should-target-playground-iframe.php`, - linksTargetingTopFrameShouldTargetPlaygroundIframe - ); - } -} - -type PatchFileCallback = (contents: string) => string | Uint8Array; -export async function updateFile( - php: UniversalPHP, - path: string, - callback: PatchFileCallback -) { - await php.writeFile(path, callback(await php.readFileAsText(path))); -} diff --git a/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php b/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php deleted file mode 100644 index 1af9810f0e..0000000000 --- a/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/1-show-admin-credentials-on-wp-login.php +++ /dev/null @@ -1,15 +0,0 @@ - - username: admin
password: password - -EOT; - } -); diff --git a/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/2-nice-error-messages-for-plugins-and-themes-directories.php b/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/2-nice-error-messages-for-plugins-and-themes-directories.php deleted file mode 100644 index 7ab5405410..0000000000 --- a/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/2-nice-error-messages-for-plugins-and-themes-directories.php +++ /dev/null @@ -1,35 +0,0 @@ -does not yet support connecting to the plugin directory yet. You can still upload plugins or install them using the Query API (e.g. ?plugin=coblocks).' - ); - } - return $res; -} ); - -add_filter( 'gettext', function( $translation ) { - // There is no better hook for swapping the error message - // on the themes page, unfortunately. - global $pagenow; - - // Only change the message on /wp-admin/theme-install.php - if( 'theme-install.php' !== $pagenow ) { - return $translation; - } - - if($translation === 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the support forums.') { - return 'Playground does not yet support connecting to the themes directory yet. You can still upload a theme or install it using the Query API (e.g. ?theme=pendant).'; - } - return $translation; -} ); diff --git a/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/3-links-targeting-top-frame-should-target-playground-iframe.php b/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/3-links-targeting-top-frame-should-target-playground-iframe.php deleted file mode 100644 index 38d9ce135c..0000000000 --- a/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/3-links-targeting-top-frame-should-target-playground-iframe.php +++ /dev/null @@ -1,21 +0,0 @@ - - - $request) { - $responses[] = false; - } - return $responses; - } - - protected static function format_get($url, $data) - { - return $url; - } - - public static function test($capabilities = array()) - { - return true; - } -} diff --git a/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/includes/requests_transport_fetch.php b/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/includes/requests_transport_fetch.php deleted file mode 100644 index e4843fc7f3..0000000000 --- a/packages/playground/remote/src/lib/web-wordpress-patches/wp-content/mu-plugins/includes/requests_transport_fetch.php +++ /dev/null @@ -1,145 +0,0 @@ - $headers, - 'data' => $data, - 'url' => $url, - 'method' => $options['type'], - ))); - - $js = <<headers = vrzno_eval($js); - - return $this->headers; - } - - public function request_multiple($requests, $options) - { - $responses = array(); - $class = get_class($this); - foreach ($requests as $id => $request) { - try { - $handler = new $class(); - $responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']); - $request['options']['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$id], $request)); - } catch (Requests_Exception $e) { - $responses[$id] = $e; - } - if (!is_string($responses[$id])) { - $request['options']['hooks']->dispatch('multiple.request.complete', array(&$responses[$id], $id)); - } - } - - return $responses; - } - - protected static function format_get($url, $data) - { - if (!empty($data)) { - $query = ''; - $url_parts = parse_url($url); - if (empty($url_parts['query'])) { - $url_parts['query'] = ''; - } else { - $query = $url_parts['query']; - } - $query .= '&' . http_build_query($data, null, '&'); - $query = trim($query, '&'); - if (empty($url_parts['query'])) { - $url .= '?' . $query; - } else { - $url = str_replace($url_parts['query'], $query, $url); - } - } - - return $url; - } - - public static function test($capabilities = array()) - { - if (!function_exists('vrzno_eval')) { - return false; - } - - if (vrzno_eval("typeof XMLHttpRequest;") !== 'function') { - return false; - } - - return true; - } -} diff --git a/packages/playground/remote/src/lib/worker-thread.ts b/packages/playground/remote/src/lib/worker-thread.ts index cb293ad55c..5d4eaa09ad 100644 --- a/packages/playground/remote/src/lib/worker-thread.ts +++ b/packages/playground/remote/src/lib/worker-thread.ts @@ -13,7 +13,6 @@ import { SupportedPHPVersion, SupportedPHPVersionsList, } from '@php-wasm/universal'; -import { applyWebWordPressPatches } from './web-wordpress-patches'; import { SyncProgressCallback, bindOpfs, @@ -175,7 +174,6 @@ try { * already applied. */ await wordPressModule; - applyWebWordPressPatches(php); await applyWordPressPatches(php, { wordpressPath: DOCROOT, patchSecrets: true,