Файловый менеджер - Редактировать - /home/harasnat/www/horse/wp-content/plugins/web-stories/includes/Admin/Cross_Origin_Isolation.php
Назад
<?php /** * Class Cross_Origin_Isolation. * * Check if editor screen, add cross origin header and add crossorigin attribute to tags. * * @link https://github.com/googleforcreators/web-stories-wp * * @copyright 2021 Google LLC * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 */ /** * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ declare(strict_types = 1); namespace Google\Web_Stories\Admin; use Google\Web_Stories\Context; use Google\Web_Stories\Infrastructure\HasRequirements; use Google\Web_Stories\Service_Base; use Google\Web_Stories\User\Preferences; /** * Class Cross_Origin_Isolation */ class Cross_Origin_Isolation extends Service_Base implements HasRequirements { /** * Context instance. * * @var Context Context instance. */ private Context $context; /** * Preferences instance. * * @var Preferences Preferences instance. */ private Preferences $preferences; /** * Constructor. * * @since 1.14.0 * * @param Preferences $preferences Preferences instance. * @param Context $context Context instance. */ public function __construct( Preferences $preferences, Context $context ) { $this->preferences = $preferences; $this->context = $context; } /** * Init */ public function register(): void { if ( ! $this->context->is_story_editor() ) { return; } add_action( 'load-post.php', [ $this, 'admin_header' ] ); add_action( 'load-post-new.php', [ $this, 'admin_header' ] ); add_filter( 'style_loader_tag', [ $this, 'style_loader_tag' ], 10, 3 ); add_filter( 'script_loader_tag', [ $this, 'script_loader_tag' ], 10, 3 ); add_filter( 'get_avatar', [ $this, 'get_avatar' ], 10, 6 ); add_action( 'wp_enqueue_media', [ $this, 'override_media_templates' ] ); } /** * Get the action to use for registering the service. * * @since 1.6.0 * * @return string Registration action to use. */ public static function get_registration_action(): string { return 'current_screen'; } /** * Get the action priority to use for registering the service. * * @since 1.6.0 * * @return int Registration action priority to use. */ public static function get_registration_action_priority(): int { return 11; } /** * Get the list of service IDs required for this service to be registered. * * @since 1.12.0 * * @return string[] List of required services. */ public static function get_requirements(): array { return [ 'user_preferences' ]; } /** * Start output buffer to add headers and `crossorigin` attribute everywhere. * * @since 1.6.0 */ public function admin_header(): void { if ( $this->needs_isolation() ) { header( 'Cross-Origin-Opener-Policy: same-origin' ); header( 'Cross-Origin-Embedder-Policy: require-corp' ); } ob_start( [ $this, 'replace_in_dom' ] ); } /** * Filters the HTML link tag of an enqueued style. * * @since 1.6.0 * * @param mixed $tag The link tag for the enqueued style. * @param string $handle The style's registered handle. * @param string $href The stylesheet's source URL. * @return string|mixed */ public function style_loader_tag( $tag, string $handle, string $href ) { return $this->add_attribute( $tag, 'href', $href ); } /** * Filters the HTML script tag of an enqueued script. * * @since 1.6.0 * * @param mixed $tag The `<script>` tag for the enqueued script. * @param string $handle The script's registered handle. * @param string $src The script's source URL. * @return string|mixed The filtered script tag. */ public function script_loader_tag( $tag, string $handle, string $src ) { return $this->add_attribute( $tag, 'src', $src ); } /** * Filter the avatar tag. * * @since 1.6.0 * * @param string|mixed $avatar HTML for the user's avatar. * @param mixed $id_or_email The avatar to retrieve. Accepts a user_id, Gravatar MD5 hash, * user email, WP_User object, WP_Post object, or WP_Comment object. * @param mixed $size Square avatar width and height in pixels to retrieve. * @param mixed $default_url URL for the default image or a default type. Accepts '404', 'retro', 'monsterid', * 'wavatar', 'indenticon', 'mystery', 'mm', 'mysteryman', 'blank', or * 'gravatar_default'. Default is the value of the 'avatar_default' option, with a * fallback of 'mystery'. * @param mixed $alt Alternative text to use in the avatar image tag. Default empty. * @param array<string,mixed> $args Arguments passed to get_avatar_data(), after processing. * @return string|mixed Filtered avatar tag. */ public function get_avatar( $avatar, $id_or_email, $size, $default_url, $alt, array $args ) { return $this->add_attribute( $avatar, 'src', $args['url'] ); } /** * Unhook wp_print_media_templates and replace with custom media templates. * * @since 1.8.0 */ public function override_media_templates(): void { remove_action( 'admin_footer', 'wp_print_media_templates' ); add_action( 'admin_footer', [ $this, 'custom_print_media_templates' ] ); } /** * Add crossorigin attribute to all tags that could have assets loaded from a different domain. * * @since 1.8.0 */ public function custom_print_media_templates(): void { ob_start(); wp_print_media_templates(); $html = (string) ob_get_clean(); $tags = [ 'audio', 'img', 'video', ]; foreach ( $tags as $tag ) { $html = (string) str_replace( '<' . $tag, '<' . $tag . ' crossorigin="anonymous"', $html ); } echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** * Determines whether "full" cross-origin isolation is needed. * * By default, `crossorigin="anonymous"` attributes are added to all external * resources to make sure they can be accessed programmatically (e.g. by html-to-image). * * However, actual cross-origin isolation by sending COOP and COEP headers is only * needed when video optimization is enabled * * @since 1.14.0 * * @link https://github.com/googleforcreators/web-stories-wp/issues/9327 * @link https://web.dev/coop-coep/ * * @return bool Whether the conditional object is needed. */ private function needs_isolation(): bool { $user_id = get_current_user_id(); if ( ! $user_id ) { return false; } // Cross-origin isolation is not needed if users can't upload files anyway. if ( ! user_can( $user_id, 'upload_files' ) ) { return false; } /** * Whether the user has opted in to video optimization. * * @var string|bool $preference */ $preference = $this->preferences->get_preference( $user_id, $this->preferences::MEDIA_OPTIMIZATION_META_KEY ); return rest_sanitize_boolean( $preference ); } /** * Process a html string and add attribute attributes to required tags. * * @since 1.6.0 * * @param string $html HTML document as string. * @return string Processed HTML document. */ protected function replace_in_dom( string $html ): string { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh $site_url = site_url(); // See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin. $tags = [ 'audio', 'img', 'link', 'script', 'video', ]; $tags = implode( '|', $tags ); $matches = []; $processed = []; if ( preg_match_all( '#<(?P<tag>' . $tags . ')[^<]*?(?:>[\s\S]*?</(?P=tag)>|\s*/>)#', $html, $matches ) ) { /** * Single match. * * @var string $match */ foreach ( $matches[0] as $index => $match ) { $tag = $matches['tag'][ $index ]; if ( str_contains( $match, ' crossorigin=' ) ) { continue; } $match_value = []; if ( ! preg_match( '/(src|href)=("([^"]+)"|\'([^\']+)\')/', $match, $match_value ) ) { continue; } $attribute = $match_value[1]; $value = $match_value[4] ?? $match_value[3] ?? ''; $cache_key = 'video' === $tag || 'audio' === $tag ? $tag : $attribute; // If already processed tag/attribute and value before, skip. if ( isset( $processed[ $cache_key ] ) && \in_array( $value, $processed[ $cache_key ], true ) ) { continue; } $processed[ $cache_key ][] = $value; // The only tags that can have <source> children. if ( 'video' === $tag || 'audio' === $tag ) { if ( ! str_starts_with( $value, $site_url ) && ! str_starts_with( $value, '/' ) ) { $html = str_replace( $match, str_replace( '<' . $tag, '<' . $tag . ' crossorigin="anonymous"', $match ), $html ); } } else { /** * Modified HTML. * * @var string $html */ $html = $this->add_attribute( $html, $attribute, $value ); } } } return $html; } /** * Do replacement to add crossorigin attribute. * * @since 1.6.0 * * @param string|mixed $html HTML string. * @param string $attribute Attribute to check for. * @param string|null|mixed $url URL. * @return string|mixed Filtered HTML string. */ protected function add_attribute( $html, string $attribute, $url ) { /** * URL. * * @var string $url */ if ( ! $url || ! \is_string( $html ) ) { return $html; } $site_url = site_url(); $url = esc_url( $url ); if ( str_starts_with( $url, $site_url ) ) { return $html; } if ( str_starts_with( $url, '/' ) ) { return $html; } return str_replace( [ $attribute . '="' . $url . '"', "{$attribute}='{$url}'", ], [ 'crossorigin="anonymous" ' . $attribute . '="' . $url . '"', "crossorigin='anonymous' {$attribute}='{$url}'", ], $html ); } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка