| @@ -2765,17 +2765,16 @@ | ||
| 2765 | 2765 | * |
| 2766 | 2766 | * @return array |
| 2767 | 2767 | */ |
| 2768 | 2768 | function sd_build_aui_styles( $args ) { |
| 2769 | - | |
| 2770 | 2769 | $styles = array(); |
| 2771 | 2770 | |
| 2772 | 2771 | // background color |
| 2773 | 2772 | if ( ! empty( $args['bg'] ) && $args['bg'] !== '' ) { |
| 2774 | 2773 | if ( $args['bg'] == 'custom-color' ) { |
| 2775 | - $styles['background-color'] = $args['bg_color']; | |
| 2774 | + $styles['background-color'] = sd_sanitize_css_color( $args['bg_color'] ); | |
| 2776 | 2775 | } elseif ( $args['bg'] == 'custom-gradient' ) { |
| 2777 | - $styles['background-image'] = $args['bg_gradient']; | |
| 2776 | + $styles['background-image'] = sd_sanitize_css_color( $args['bg_gradient'] ); | |
| 2778 | 2777 | |
| 2779 | 2778 | // use background on text. |
| 2780 | 2779 | if ( ! empty( $args['bg_on_text'] ) && $args['bg_on_text'] ) { |
| 2781 | 2780 | $styles['background-clip'] = 'text'; |
| @@ -2829,9 +2828,9 @@ | ||
| 2829 | 2828 | } |
| 2830 | 2829 | |
| 2831 | 2830 | // font color |
| 2832 | 2831 | if ( ! empty( $args['text_color_custom'] ) && $args['text_color_custom'] !== '' ) { |
| 2833 | - $styles['color'] = esc_attr( $args['text_color_custom'] ); | |
| 2832 | + $styles['color'] = sd_sanitize_css_color( $args['text_color_custom'] ); | |
| 2834 | 2833 | } |
| 2835 | 2834 | |
| 2836 | 2835 | // font line height |
| 2837 | 2836 | if ( ! empty( $args['font_line_height'] ) && $args['font_line_height'] !== '' ) { |
| @@ -2863,28 +2862,39 @@ | ||
| 2863 | 2862 | * @return string |
| 2864 | 2863 | */ |
| 2865 | 2864 | function sd_build_hover_styles( $args, $is_preview = false ) { |
| 2866 | 2865 | $rules = ''; |
| 2866 | + | |
| 2867 | 2867 | // text color |
| 2868 | 2868 | if ( ! empty( $args['styleid'] ) ) { |
| 2869 | - $styleid = $is_preview ? 'html .editor-styles-wrapper .' . esc_attr( $args['styleid'] ) : 'html .' . esc_attr( $args['styleid'] ); | |
| 2869 | + // The style id is used as a CSS class selector, so only class-safe characters may survive. | |
| 2870 | + $styleid_classes = array_filter( array_map( 'sanitize_html_class', explode( ' ', (string) $args['styleid'] ) ) ); | |
| 2870 | 2871 | |
| 2871 | - // text | |
| 2872 | + if ( empty( $styleid_classes ) ) { | |
| 2873 | + return ''; | |
| 2874 | + } | |
| 2875 | + | |
| 2876 | + $styleid_class = implode( '.', $styleid_classes ); | |
| 2877 | + $styleid = $is_preview ? 'html .editor-styles-wrapper .' . $styleid_class : 'html .' . $styleid_class; | |
| 2878 | + | |
| 2879 | + // text_color_hover | |
| 2872 | 2880 | if ( ! empty( $args['text_color_hover'] ) ) { |
| 2873 | 2881 | $key = 'custom' === $args['text_color_hover'] && ! empty( $args['text_color_hover_custom'] ) ? 'text_color_hover_custom' : 'text_color_hover'; |
| 2874 | - $color = sd_get_color_from_var( $args[ $key ] ); | |
| 2882 | + $color = sd_sanitize_css_color( $args[ $key ], 'inherit' ); | |
| 2883 | + $color = sd_get_color_from_var( $color ); | |
| 2875 | 2884 | $rules .= $styleid . ':hover {color: ' . $color . ' !important;} '; |
| 2876 | 2885 | } |
| 2877 | 2886 | |
| 2878 | - // bg | |
| 2887 | + // bg_hover | |
| 2879 | 2888 | if ( ! empty( $args['bg_hover'] ) ) { |
| 2880 | 2889 | if ( 'custom-gradient' === $args['bg_hover'] ) { |
| 2881 | - $color = $args['bg_hover_gradient']; | |
| 2890 | + $color = sd_sanitize_css_color( $args['bg_hover_gradient'], 'inherit' ); | |
| 2882 | 2891 | $rules .= $styleid . ':hover {background-image: ' . $color . ' !important;} '; |
| 2883 | 2892 | $rules .= $styleid . '.btn:hover {border-color: transparent !important;} '; |
| 2884 | 2893 | } else { |
| 2885 | 2894 | $key = 'custom-color' === $args['bg_hover'] ? 'bg_hover_color' : 'bg_hover'; |
| 2886 | - $color = sd_get_color_from_var( $args[ $key ] ); | |
| 2895 | + $color = sd_sanitize_css_color( $args[ $key ], 'inherit' ); | |
| 2896 | + $color = sd_get_color_from_var( $color ); | |
| 2887 | 2897 | $rules .= $styleid . ':hover {background: ' . $color . ' !important;} '; |
| 2888 | 2898 | $rules .= $styleid . '.btn:hover {border-color: ' . $color . ' !important;} '; |
| 2889 | 2899 | } |
| 2890 | 2900 | } |
| @@ -2900,9 +2910,8 @@ | ||
| 2900 | 2910 | * |
| 2901 | 2911 | * @return mixed|string |
| 2902 | 2912 | */ |
| 2903 | 2913 | function sd_get_color_from_var( $var ) { |
| 2904 | - | |
| 2905 | 2914 | //sanitize_hex_color() @todo this does not cover transparency |
| 2906 | 2915 | if ( strpos( $var, '#' ) === false ) { |
| 2907 | 2916 | $var = defined( 'BLOCKSTRAP_BLOCKS_VERSION' ) ? 'var(--wp--preset--color--' . esc_attr( $var ) . ')' : 'var(--' . esc_attr( $var ) . ')'; |
| 2908 | 2917 | } |
| @@ -2910,8 +2919,38 @@ | ||
| 2910 | 2919 | return $var; |
| 2911 | 2920 | } |
| 2912 | 2921 | |
| 2913 | 2922 | /** |
| 2923 | + * Sanitizes a CSS color value. | |
| 2924 | + * | |
| 2925 | + * @since 1.2.37 | |
| 2926 | + * | |
| 2927 | + * @param string $color The color value to sanitize. | |
| 2928 | + * @param string $default Optional. Value to return when the color is empty or unsafe. Default empty. | |
| 2929 | + * @return string Sanitized color value or default. | |
| 2930 | + */ | |
| 2931 | +function sd_sanitize_css_color( $color, $default = '' ) { | |
| 2932 | + if ( ! is_scalar( $color ) || $color === '' ) { | |
| 2933 | + return $default; | |
| 2934 | + } | |
| 2935 | + | |
| 2936 | + // Remove CSS comments, which can hide things like expression/**/( or url/**/(. | |
| 2937 | + $color = preg_replace( '#/\*.*?(\*/|$)#s', '', (string) $color ); | |
| 2938 | + | |
| 2939 | + // Keep only the part before the first ; { or }. | |
| 2940 | + $color = trim( preg_split( '/[;{}]/', $color )[0] ); | |
| 2941 | + | |
| 2942 | + // Allow trailing !important. | |
| 2943 | + $value = preg_replace( '/\s*!important$/i', '', $color ); | |
| 2944 | + | |
| 2945 | + if ( $value === '' || preg_match( '/[^\w\s#%.,()\/*+-]|url\s*\(|expression\s*\(/i', $value ) ) { | |
| 2946 | + return $default; | |
| 2947 | + } | |
| 2948 | + | |
| 2949 | + return $color; | |
| 2950 | +} | |
| 2951 | + | |
| 2952 | +/** | |
| 2914 | 2953 | * Sanitize single or multiple HTML classes. |
| 2915 | 2954 | * |
| 2916 | 2955 | * @param $classes |
| 2917 | 2956 | * @param $sep |
| @@ -3404,10 +3443,39 @@ | ||
| 3404 | 3443 | return apply_filters( 'sd_render_block_visibility_content', $block_content, $_block_content, $attributes, $block, $instance, $check_rules ); |
| 3405 | 3444 | } |
| 3406 | 3445 | add_filter( 'render_block', 'sd_render_block', 9, 3 ); |
| 3407 | 3446 | |
| 3447 | +/** | |
| 3448 | + * Safely fetches page content after checking viewing permissions. | |
| 3449 | + * | |
| 3450 | + * @param int $post_id The ID of the post/page. | |
| 3451 | + * @param bool $bypass_check Set to true only if called from a secure, trusted admin context. | |
| 3452 | + * @return string | |
| 3453 | + */ | |
| 3454 | +function sd_get_safe_post_content( $post_id, $bypass_check = false ) { | |
| 3455 | + $post_id = (int) $post_id; | |
| 3456 | + | |
| 3457 | + if ( $post_id <= 0 ) { | |
| 3458 | + return ''; | |
| 3459 | + } | |
| 3460 | + | |
| 3461 | + if ( ! $bypass_check ) { | |
| 3462 | + $post = get_post( $post_id ); | |
| 3463 | + | |
| 3464 | + if ( empty( $post ) ) { | |
| 3465 | + return ''; | |
| 3466 | + } | |
| 3467 | + | |
| 3468 | + if ( ( ! is_post_publicly_viewable( $post ) && ! current_user_can( 'read_post', $post_id ) ) || post_password_required( $post ) ) { | |
| 3469 | + return ''; | |
| 3470 | + } | |
| 3471 | + } | |
| 3472 | + | |
| 3473 | + return get_post_field( 'post_content', $post_id ); | |
| 3474 | +} | |
| 3475 | + | |
| 3408 | 3476 | function sd_get_page_content( $page_id ) { |
| 3409 | - $content = $page_id > 0 ? get_post_field( 'post_content', (int) $page_id ) : ''; | |
| 3477 | + $content = sd_get_safe_post_content( (int) $page_id ); | |
| 3410 | 3478 | |
| 3411 | 3479 | // Maybe bypass content |
| 3412 | 3480 | $bypass_content = apply_filters( 'sd_bypass_page_content', '', $content, $page_id ); |
| 3413 | 3481 | if ( $bypass_content ) { |