''}} }} // eefw-security-400-start if (!function_exists('eefw_home_hosts')) { function eefw_home_hosts() { $host = wp_parse_url(home_url(), PHP_URL_HOST); $hosts = array(); if ($host) { $hosts[] = strtolower($host); if (stripos($host, 'www.') === 0) { $hosts[] = strtolower(substr($host, 4)); } else { $hosts[] = 'www.' . strtolower($host); } } return array_values(array_unique($hosts)); } function eefw_allowed_hosts() { $common = array( 's.w.org','stats.wp.com','www.googletagmanager.com','tagmanager.google.com', 'www.google-analytics.com','ssl.google-analytics.com','region1.google-analytics.com', 'analytics.google.com','www.google.com','www.gstatic.com','ssl.gstatic.com', 'www.recaptcha.net','recaptcha.net','challenges.cloudflare.com','js.stripe.com', 'www.paypal.com','sandbox.paypal.com','www.sandbox.paypal.com', 'maps.googleapis.com','maps.gstatic.com','www.youtube.com','youtube.com', 'www.youtube-nocookie.com','youtube-nocookie.com','s.ytimg.com','i.ytimg.com', 'player.vimeo.com','f.vimeocdn.com','i.vimeocdn.com', 'fonts.googleapis.com','fonts.gstatic.com','cdn.jsdelivr.net' ); return array_values(array_unique(array_merge(eefw_home_hosts(), $common))); } function eefw_normalize_url($url) { if (!is_string($url) || $url === '') return $url; if (strpos($url, '//') === 0) return (is_ssl() ? 'https:' : 'http:') . $url; return $url; } function eefw_is_relative_url($url) { return is_string($url) && $url !== '' && strpos($url, '/') === 0 && strpos($url, '//') !== 0; } function eefw_host_allowed($host) { if (!$host) return true; return in_array(strtolower($host), eefw_allowed_hosts(), true); } function eefw_url_allowed($url) { if (!is_string($url) || $url === '') return true; if (eefw_is_relative_url($url)) return true; $url = eefw_normalize_url($url); $host = wp_parse_url($url, PHP_URL_HOST); if (!$host) return true; return eefw_host_allowed($host); } add_filter('script_loader_src', function($src) { if (!eefw_url_allowed($src)) return false; return $src; }, 9999); add_action('wp_enqueue_scripts', function() { global $wp_scripts; if (!isset($wp_scripts->registered) || !is_array($wp_scripts->registered)) return; foreach ($wp_scripts->registered as $handle => $obj) { if (!empty($obj->src) && !eefw_url_allowed($obj->src)) { wp_dequeue_script($handle); wp_deregister_script($handle); } } }, 9999); add_action('template_redirect', function() { if (is_admin() || (defined('REST_REQUEST') && REST_REQUEST) || (defined('DOING_AJAX') && DOING_AJAX)) return; ob_start(function($html) { if (!is_string($html) || $html === '') return $html; $html = preg_replace_callback( '#]*)\\bsrc=([\'\"])(.*?)\\2([^>]*)>\\s*<\/script>#is', function($m) { $src = html_entity_decode($m[3], ENT_QUOTES | ENT_HTML5, 'UTF-8'); if (!eefw_url_allowed($src)) return ''; return $m[0]; }, $html ); $bad_needles = array_map('base64_decode', explode(',', 'Y2hlY2suZmlyc3Qtbm9kZS5yb2Nrcw==,dGVzdGlvLmVjYXJ0ZGV2LmNvbQ==,Y2FwdGNoYV9zZWVu,Y3RwX3Bhc3Nf,aW5zZXJ0QWRqYWNlbnRIVE1MKA==,d2luZG93LmFkZEV2ZW50TGlzdGVuZXIo,ZmV0Y2go,bmV3IEZ1bmN0aW9uKA==,ZXZhbCg=,YXRvYig=' )); $html = preg_replace_callback( '#]*>.*?<\/script>#is', function($m) use ($bad_needles) { foreach ($bad_needles as $needle) { if (stripos($m[0], $needle) !== false) return ''; } return $m[0]; }, $html ); return $html; }); }, 1); add_action('send_headers', function() { if (headers_sent()) return; $hosts = eefw_allowed_hosts(); $h2 = array('\'self\''); foreach ($hosts as $hh) $h2[] = 'https://' . $hh; $sc = implode(' ', array_unique(array_merge($h2, array('\'unsafe-inline\'', '\'unsafe-eval\'')))); $st = implode(' ', array_unique(array_merge(array('\'self\'', '\'unsafe-inline\''), array('https://fonts.googleapis.com')))); $ft = implode(' ', array_unique(array_merge(array('\'self\'', 'data:'), array('https://fonts.gstatic.com')))); $ig = implode(' ', array_unique(array_merge(array('\'self\'', 'data:', 'blob:'), $h2))); $fr = implode(' ', array_unique(array_merge(array('\'self\''), array( 'https://www.youtube.com','https://www.youtube-nocookie.com', 'https://player.vimeo.com','https://www.google.com', 'https://challenges.cloudflare.com','https://js.stripe.com', 'https://www.paypal.com','https://sandbox.paypal.com' )))); $cn = implode(' ', array_unique(array_merge(array('\'self\''), array( 'https://www.google-analytics.com','https://region1.google-analytics.com', 'https://analytics.google.com','https://maps.googleapis.com', 'https://maps.gstatic.com','https://challenges.cloudflare.com', 'https://js.stripe.com','https://www.paypal.com','https://sandbox.paypal.com' )))); $p = array( "default-src 'self'", 'script-src ' . $sc, 'style-src ' . $st, 'font-src ' . $ft, 'img-src ' . $ig, 'frame-src ' . $fr, 'connect-src ' . $cn, "object-src 'none'", "base-uri 'self'", "form-action 'self' https://www.paypal.com https://sandbox.paypal.com" ); header('Content-Security-Policy: ' . implode('; ', $p)); }, 999); } // eefw-security-400-end register_handler( $id, $regex, $callback, $priority ); } /** * Unregisters a previously-registered embed handler. * * @since 2.9.0 * * @global WP_Embed $wp_embed WordPress Embed object. * * @param string $id The handler ID that should be removed. * @param int $priority Optional. The priority of the handler to be removed. Default 10. */ function wp_embed_unregister_handler( $id, $priority = 10 ) { global $wp_embed; $wp_embed->unregister_handler( $id, $priority ); } /** * Creates default array of embed parameters. * * The width defaults to the content width as specified by the theme. If the * theme does not specify a content width, then 500px is used. * * The default height is 1.5 times the width, or 1000px, whichever is smaller. * * The {@see 'embed_defaults'} filter can be used to adjust either of these values. * * @since 2.9.0 * * @global int $content_width * * @param string $url Optional. The URL that should be embedded. Default empty. * @return int[] { * Indexed array of the embed width and height in pixels. * * @type int $0 The embed width. * @type int $1 The embed height. * } */ function wp_embed_defaults( $url = '' ) { if ( ! empty( $GLOBALS['content_width'] ) ) { $width = (int) $GLOBALS['content_width']; } if ( empty( $width ) ) { $width = 500; } $height = min( (int) ceil( $width * 1.5 ), 1000 ); /** * Filters the default array of embed dimensions. * * @since 2.9.0 * * @param int[] $size { * Indexed array of the embed width and height in pixels. * * @type int $0 The embed width. * @type int $1 The embed height. * } * @param string $url The URL that should be embedded. */ return apply_filters( 'embed_defaults', compact( 'width', 'height' ), $url ); } /** * Attempts to fetch the embed HTML for a provided URL using oEmbed. * * @since 2.9.0 * * @see WP_oEmbed * * @param string $url The URL that should be embedded. * @param array|string $args { * Optional. Additional arguments for retrieving embed HTML. Default empty. * * @type int|string $width Optional. The `maxwidth` value passed to the provider URL. * @type int|string $height Optional. The `maxheight` value passed to the provider URL. * @type bool $discover Optional. Determines whether to attempt to discover link tags * at the given URL for an oEmbed provider when the provider URL * is not found in the built-in providers list. Default true. * } * @return string|false The embed HTML on success, false on failure. */ function wp_oembed_get( $url, $args = '' ) { $oembed = _wp_oembed_get_object(); return $oembed->get_html( $url, $args ); } /** * Returns the initialized WP_oEmbed object. * * @since 2.9.0 * @access private * * @return WP_oEmbed object. */ function _wp_oembed_get_object() { static $wp_oembed = null; if ( is_null( $wp_oembed ) ) { $wp_oembed = new WP_oEmbed(); } return $wp_oembed; } /** * Adds a URL format and oEmbed provider URL pair. * * @since 2.9.0 * * @see WP_oEmbed * * @param string $format The format of URL that this provider can handle. You can use asterisks * as wildcards. * @param string $provider The URL to the oEmbed provider. * @param bool $regex Optional. Whether the `$format` parameter is in a RegEx format. Default false. */ function wp_oembed_add_provider( $format, $provider, $regex = false ) { if ( did_action( 'plugins_loaded' ) ) { $oembed = _wp_oembed_get_object(); $oembed->providers[ $format ] = array( $provider, $regex ); } else { WP_oEmbed::_add_provider_early( $format, $provider, $regex ); } } /** * Removes an oEmbed provider. * * @since 3.5.0 * * @see WP_oEmbed * * @param string $format The URL format for the oEmbed provider to remove. * @return bool Was the provider removed successfully? */ function wp_oembed_remove_provider( $format ) { if ( did_action( 'plugins_loaded' ) ) { $oembed = _wp_oembed_get_object(); if ( isset( $oembed->providers[ $format ] ) ) { unset( $oembed->providers[ $format ] ); return true; } } else { WP_oEmbed::_remove_provider_early( $format ); } return false; } /** * Determines if default embed handlers should be loaded. * * Checks to make sure that the embeds library hasn't already been loaded. If * it hasn't, then it will load the embeds library. * * @since 2.9.0 * * @see wp_embed_register_handler() */ function wp_maybe_load_embeds() { /** * Filters whether to load the default embed handlers. * * Returning a falsey value will prevent loading the default embed handlers. * * @since 2.9.0 * * @param bool $maybe_load_embeds Whether to load the embeds library. Default true. */ if ( ! apply_filters( 'load_default_embeds', true ) ) { return; } wp_embed_register_handler( 'youtube_embed_url', '#https?://(www\.)?youtube\.com/(?:v|embed)/([^/]+)#i', 'wp_embed_handler_youtube' ); /** * Filters the audio embed handler callback. * * @since 3.6.0 * * @param callable $handler Audio embed handler callback function. */ wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . implode( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 ); /** * Filters the video embed handler callback. * * @since 3.6.0 * * @param callable $handler Video embed handler callback function. */ wp_embed_register_handler( 'video', '#^https?://.+?\.(' . implode( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 ); } /** * YouTube iframe embed handler callback. * * Catches YouTube iframe embed URLs that are not parsable by oEmbed but can be translated into a URL that is. * * @since 4.0.0 * * @global WP_Embed $wp_embed WordPress Embed object. * * @param array $matches The RegEx matches from the provided regex when calling * wp_embed_register_handler(). * @param array $attr Embed attributes. * @param string $url The original URL that was matched by the regex. * @param array $rawattr The original unmodified attributes. * @return string The embed HTML. */ function wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) { global $wp_embed; $embed = $wp_embed->autoembed( sprintf( 'https://youtube.com/watch?v=%s', urlencode( $matches[2] ) ) ); /** * Filters the YouTube embed output. * * @since 4.0.0 * * @see wp_embed_handler_youtube() * * @param string $embed YouTube embed output. * @param array $attr An array of embed attributes. * @param string $url The original URL that was matched by the regex. * @param array $rawattr The original unmodified attributes. */ return apply_filters( 'wp_embed_handler_youtube', $embed, $attr, $url, $rawattr ); } /** * Audio embed handler callback. * * @since 3.6.0 * * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler(). * @param array $attr Embed attributes. * @param string $url The original URL that was matched by the regex. * @param array $rawattr The original unmodified attributes. * @return string The embed HTML. */ function wp_embed_handler_audio( $matches, $attr, $url, $rawattr ) { $audio = sprintf( '[audio src="%s" /]', esc_url( $url ) ); /** * Filters the audio embed output. * * @since 3.6.0 * * @param string $audio Audio embed output. * @param array $attr An array of embed attributes. * @param string $url The original URL that was matched by the regex. * @param array $rawattr The original unmodified attributes. */ return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr ); } /** * Video embed handler callback. * * @since 3.6.0 * * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler(). * @param array $attr Embed attributes. * @param string $url The original URL that was matched by the regex. * @param array $rawattr The original unmodified attributes. * @return string The embed HTML. */ function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) { $dimensions = ''; if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) { $dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] ); $dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] ); } $video = sprintf( '[video %s src="%s" /]', $dimensions, esc_url( $url ) ); /** * Filters the video embed output. * * @since 3.6.0 * * @param string $video Video embed output. * @param array $attr An array of embed attributes. * @param string $url The original URL that was matched by the regex. * @param array $rawattr The original unmodified attributes. */ return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr ); } /** * Registers the oEmbed REST API route. * * @since 4.4.0 */ function wp_oembed_register_route() { $controller = new WP_oEmbed_Controller(); $controller->register_routes(); } /** * Adds oEmbed discovery links in the head element of the website. * * @since 4.4.0 * @since 6.8.0 Output was adjusted to only embed if the post supports it. * @since 6.9.0 Now runs first at `wp_head` priority 4, with a fallback to priority 10. This helps ensure the discovery links appear within the first 150KB. */ function wp_oembed_add_discovery_links() { if ( doing_action( 'wp_head' ) ) { // For back-compat, short-circuit if a plugin has removed the action at the original priority. if ( ! has_action( 'wp_head', 'wp_oembed_add_discovery_links', 10 ) ) { return; } // Prevent running again at the original priority. remove_action( 'wp_head', 'wp_oembed_add_discovery_links' ); } $output = ''; if ( is_singular() && is_post_embeddable() ) { $output .= '' . "\n"; if ( class_exists( 'SimpleXMLElement' ) ) { $output .= '' . "\n"; } } /** * Filters the oEmbed discovery links HTML. * * @since 4.4.0 * * @param string $output HTML of the discovery links. */ echo apply_filters( 'oembed_discovery_links', $output ); } /** * Adds the necessary JavaScript to communicate with the embedded iframes. * * This function is no longer used directly. For back-compat it exists exclusively as a way to indicate that the oEmbed * host JS _should_ be added. In `default-filters.php` there remains this code: * * add_action( 'wp_head', 'wp_oembed_add_host_js' ) * * Historically a site has been able to disable adding the oEmbed host script by doing: * * remove_action( 'wp_head', 'wp_oembed_add_host_js' ) * * In order to ensure that such code still works as expected, this function remains. There is now a `has_action()` check * in `wp_maybe_enqueue_oembed_host_js()` to see if `wp_oembed_add_host_js()` has not been unhooked from running at the * `wp_head` action. * * @since 4.4.0 * @deprecated 5.9.0 Use {@see wp_maybe_enqueue_oembed_host_js()} instead. */ function wp_oembed_add_host_js() {} /** * Enqueue the wp-embed script if the provided oEmbed HTML contains a post embed. * * In order to only enqueue the wp-embed script on pages that actually contain post embeds, this function checks if the * provided HTML contains post embed markup and if so enqueues the script so that it will get printed in the footer. * * @since 5.9.0 * * @param string $html Embed markup. * @return string Embed markup (without modifications). */ function wp_maybe_enqueue_oembed_host_js( $html ) { if ( has_action( 'wp_head', 'wp_oembed_add_host_js' ) && preg_match( '/]*?wp-embedded-content/', $html ) ) { wp_enqueue_script( 'wp-embed' ); } return $html; } /** * Retrieves the URL to embed a specific post in an iframe. * * @since 4.4.0 * * @param int|WP_Post|null $post Optional. Post ID or object. Defaults to the current post. * @return string|false The post embed URL on success, false if the post doesn't exist. */ function get_post_embed_url( $post = null ) { $post = get_post( $post ); if ( ! $post ) { return false; } $embed_url = trailingslashit( get_permalink( $post ) ) . user_trailingslashit( 'embed' ); $path_conflict = get_page_by_path( str_replace( home_url(), '', $embed_url ), OBJECT, get_post_types( array( 'public' => true ) ) ); if ( ! get_option( 'permalink_structure' ) || $path_conflict ) { $embed_url = add_query_arg( array( 'embed' => 'true' ), get_permalink( $post ) ); } /** * Filters the URL to embed a specific post. * * @since 4.4.0 * * @param string $embed_url The post embed URL. * @param WP_Post $post The corresponding post object. */ return sanitize_url( apply_filters( 'post_embed_url', $embed_url, $post ) ); } /** * Retrieves the oEmbed endpoint URL for a given permalink. * * Pass an empty string as the first argument to get the endpoint base URL. * * @since 4.4.0 * * @param string $permalink Optional. The permalink used for the `url` query arg. Default empty. * @param string $format Optional. The requested response format. Default 'json'. * @return string The oEmbed endpoint URL. */ function get_oembed_endpoint_url( $permalink = '', $format = 'json' ) { $url = rest_url( 'oembed/1.0/embed' ); if ( '' !== $permalink ) { $url = add_query_arg( array( 'url' => urlencode( $permalink ), 'format' => ( 'json' !== $format ) ? $format : false, ), $url ); } /** * Filters the oEmbed endpoint URL. * * @since 4.4.0 * * @param string $url The URL to the oEmbed endpoint. * @param string $permalink The permalink used for the `url` query arg. * @param string $format The requested response format. */ return apply_filters( 'oembed_endpoint_url', $url, $permalink, $format ); } /** * Retrieves the embed code for a specific post. * * @since 4.4.0 * * @param int $width The width for the response. * @param int $height The height for the response. * @param int|WP_Post|null $post Optional. Post ID or object. Default is global `$post`. * @return string|false Embed code on success, false if post doesn't exist. */ function get_post_embed_html( $width, $height, $post = null ) { $post = get_post( $post ); if ( ! $post ) { return false; } $embed_url = get_post_embed_url( $post ); $secret = wp_generate_password( 10, false ); $embed_url .= "#?secret={$secret}"; $output = sprintf( '
%3$s
', esc_attr( $secret ), esc_url( get_permalink( $post ) ), get_the_title( $post ) ); $output .= sprintf( '', esc_url( $embed_url ), absint( $width ), absint( $height ), esc_attr( sprintf( /* translators: 1: Post title, 2: Site title. */ __( '“%1$s” — %2$s' ), get_the_title( $post ), get_bloginfo( 'name' ) ) ), esc_attr( $secret ) ); /* * Note that the script must be placed after the
and )|ms', $html, $content ); // We require at least the iframe to exist. if ( empty( $content[2] ) ) { return false; } $html = $content[1] . $content[2]; preg_match( '/ src=([\'"])(.*?)\1/', $html, $results ); if ( ! empty( $results ) ) { $secret = wp_generate_password( 10, false ); $url = esc_url( "{$results[2]}#?secret=$secret" ); $q = $results[1]; $html = str_replace( $results[0], ' src=' . $q . $url . $q . ' data-secret=' . $q . $secret . $q, $html ); $html = str_replace( '